home *** CD-ROM | disk | FTP | other *** search
/ Fritz: All Fritz / All Fritz.zip / All Fritz / FILES / PROGBLER / WHIZZARD.LZH / COMPRINT.ASM < prev    next >
Assembly Source File  |  1984-06-16  |  20KB  |  815 lines

  1. COMMENT *
  2.  
  3.                  CLUBware  (tm)
  4.  
  5.       COMPRINT - Enhancement to the Basic Compiler Print statement
  6.                 (for routines compiled without /O option)
  7.  
  8.            Copyright 1984 Rayhawk Automation N.W. Inc
  9.                   P.O. Box 1427
  10.                   Beaverton, Oregon   97075
  11.                                           *
  12.  
  13. SCRDSEG   SEGMENT
  14.  
  15.       ASSUME  CS:SCRDSEG,DS:NOTHING,ES:NOTHING,SS:STACK
  16.  
  17. ORIG_INT10      LABEL  WORD           ; original int 10
  18.       DW      0
  19.       DW      0
  20.  
  21.  
  22. ;______________________________________________________________________________
  23.  
  24. ;   Swap the code used by BASIC to print strings.  Swap must be made
  25. ;    after BASIC has been loaded and initialized its environment.  When the
  26. ;    screen is cleared INTSWAP intercepts the BASIC print statement.
  27.  
  28. ORIG_2841      LABEL  WORD           ; original subroutine 2841
  29.       DW      2846h
  30. BASIC_SEGMENT      LABEL  WORD
  31.       DW      0
  32.  
  33. CALLERS_SEG      EQU  WORD PTR [BP+4]    ; location of callers segment on stack
  34.  
  35.  
  36. INTSWAP   PROC      FAR
  37.  
  38.       CMP      AX,0600h           ; clear screen request?
  39.       JE      DO_SWAP
  40.       JMP      DWORD PTR ORIG_INT10 ; pass call to BIOS
  41.  
  42. DO_SWAP:
  43.       PUSH      BP               ; address the stack
  44.       MOV      BP,SP
  45.       PUSH      DS
  46.       PUSH      AX
  47.  
  48.       MOV      AX,CALLERS_SEG       ; address basic space
  49.       MOV      DS,AX
  50.       MOV      BASIC_SEGMENT,AX     ; save basic's code segment
  51.  
  52.       CLI                   ; disable interrupts for a moment
  53.  
  54. ;   have we already taken over this subroutine once before?
  55.  
  56.       CMP      WORD PTR DS:[2844h],SEG PRINTER
  57.       JE      ALREADY_SAVED
  58.  
  59.  
  60. ;   replace the original code with a call to PRINTER to intercept prints
  61.  
  62.       CMP      WORD PTR DS:[2842h],OFFSET PRINTER  ; two copies of INTSWAP?
  63.       JE      SECOND_COPY
  64.       CMP      WORD PTR DS:[2841h],8B56h          ; basic loaded yet?
  65.       JNE      ALREADY_SAVED               ; jump if not
  66.  
  67. SECOND_COPY:
  68.       MOV      BYTE PTR DS:[2841h],9Ah          ; opcode is far call
  69.       MOV      WORD PTR DS:[2842h],OFFSET PRINTER  ; target for call
  70.       MOV      WORD PTR DS:[2844h],SEG    PRINTER
  71.  
  72. ALREADY_SAVED:
  73.  
  74.       STI
  75.  
  76.       POP      AX
  77.       POP      DS
  78.       POP      BP
  79.       JMP      DWORD PTR ORIG_INT10 ; pass clear screen to BIOS now
  80.  
  81.  
  82.  
  83. INTSWAP   ENDP
  84.  
  85. ;______________________________________________________________________________
  86.  
  87. COMMENT * PRINTER prints a character string on the screen starting
  88.           at the current cursor position.  After the string is
  89.           written to the screen the cursor position is updated
  90.           to just after the string.
  91.  
  92.       To use this routine, a clear screen must occur
  93.           to swap in the PRINTER routine for basic.
  94.  
  95.  
  96.       The COMPRINT module will take over the INT 10h and make
  97.           this module permanently resident.  The user from inside
  98.           his BASIC program will clear the screen with a CLS
  99.           which will perform the vector swap.
  100.  
  101.       Algorithm:
  102.  
  103.          check context for simple text to screen or possibly something
  104.            more involved that basic should handle
  105.  
  106.           1) backup to start of string and store character count
  107.           2) load current page from DS:[0085]
  108.           3) load current position on page from DS:[0087]
  109.           4) load attribute for string from DS:[00B5]
  110.           5) move character count to CX for use in loop
  111.           6) load type of crt display from 0000:463
  112.           7) address the screen segment
  113.           8) move string to screen while synchronizing
  114.               with horizontal retrace
  115.           9) update cursor position on screen
  116.          10) update cursor position in database at DS:[0087]
  117.          11) leave registers in manner BASIC expects
  118.  
  119.       On entry
  120.           DS:[SI] points to string to write
  121.           CX      contains count of characters to write
  122.           DS:[0085] contains the page to which we write
  123.           DS:[00B5] contains the attribute for the text
  124.           DS:[0087] contains the current screen location and must
  125.                    be updated after print is complete
  126.  
  127.  
  128.                                           *
  129. ;______________________________________________________________________________
  130.  
  131. ;  Local data addressable through CS register
  132.  
  133.  
  134. CHAR_COUNT      LABEL  WORD
  135.       DW      0
  136.  
  137.  
  138. LINE_START      LABEL  WORD
  139.       DW      0               ;  0
  140.       DW      160               ;  1
  141.       DW      320               ;  2
  142.       DW      480               ;  3
  143.       DW      640               ;  4
  144.       DW      800               ;  5
  145.       DW      960               ;  6
  146.       DW      1120               ;  7
  147.       DW      1280               ;  8
  148.       DW      1440               ;  9
  149.  
  150.       DW      1600               ;  10
  151.       DW      1760               ;  11
  152.       DW      1920               ;  12
  153.       DW      2080               ;  13
  154.       DW      2240               ;  14
  155.       DW      2400               ;  15
  156.       DW      2560               ;  16
  157.       DW      2720               ;  17
  158.       DW      2880               ;  18
  159.       DW      3040               ;  19
  160.       DW      3200               ;  20
  161.       DW      3360               ;  21
  162.       DW      3520               ;  22
  163.       DW      3680               ;  23
  164.       DW      3840               ;  24
  165.  
  166. PAGE_START      LABEL  WORD
  167.       DW      0
  168.       DW      4000
  169.       DW      8000
  170.       DW      12000
  171.  
  172. STARTING_PAGE      LABEL  WORD
  173.       DW      0
  174.  
  175. END_OF_PAGE      LABEL  WORD
  176.       DW      0
  177.  
  178. STARTING_LINE      LABEL  WORD
  179.       DW      0
  180.  
  181. RESIDUAL      LABEL  WORD
  182.       DW      0
  183.  
  184.  
  185. LOCAL_FLAG      LABEL  BYTE
  186.           DB   00000000b
  187. JUST_BLANKS      EQU  00000001b       ; basic wants just blanks displayed
  188. ZERO_TAGGED      EQU  00000010b       ; string length unknown, tagged by 0
  189.  
  190.  
  191. ;______________________________________________________________________________
  192.  
  193. COMMENT *
  194.  
  195.    New PRINT service routine for BASIC
  196.  
  197.      Calls to routine XXXX:2841 are rerouted to this piece of code
  198.      These calls come from several places within the BASIC rutime library
  199.      We service calls from three locations: 4A07 - call to display a string
  200.                         4ECE - call to display blanks
  201.                         612F - call to display number
  202.      Calls from anywhere else are serviced by the original basic code.
  203.      The three labels corresponding to the three types of calls we service
  204.      are  STRING_IO
  205.       REPEAT_BLANKS
  206.       NUMBER_STRING
  207.      The code labeled BASIC_IO passes the interrupt back to the basic code
  208.      for service.
  209.                                           *
  210.  
  211.  
  212. PRINTER   PROC      FAR
  213.  
  214.       PUSH      BP
  215.       MOV      BP,SP            ; address the stack
  216.       MOV      LOCAL_FLAG,0           ; clear the flag for string i/o
  217.  
  218.  
  219. ;    check context for simple text to screen or possibly something
  220. ;      more involved that basic should handle
  221.  
  222.       CMP      WORD PTR DS:[079Eh],0
  223.       JNE      BASIC_IO
  224.       CMP      BYTE PTR DS:[07CCh],50h  ; 80 bytes per line?
  225.       JNE      BASIC_IO
  226. ;      CMP      BYTE PTR DS:[0056h],25   ; on bottom line of screen?
  227. ;      JE      BASIC_IO           ; if so, let basic handle it
  228.       CMP      WORD PTR [BP+6],4A07h  ; just regular i/o?
  229.       JE      STRING_IO
  230.       CMP      WORD PTR [BP+6],4ECEh  ; just repeated blanks?
  231.       JE      REPEAT_BLANKS
  232.       CMP      WORD PTR [BP+6],612Fh  ; number string?
  233.       JE      NUMBER_STRING
  234.  
  235. ;    allow original service routine to perform I/O
  236.  
  237. BASIC_IO:
  238.       POP      BP
  239.       ADD      SP,4               ; clear our far call from stack
  240.       PUSH      SI               ; original first two statements
  241.       MOV      SI,WORD PTR DS:[079Eh] ;   of the basic subroutine
  242.       JMP      DWORD PTR ORIG_2841  ; pass control to original routine
  243.  
  244.  
  245.  
  246. ; ----------
  247.  
  248.  
  249. ;    send a number string to screen
  250. ;          string length is not known but end is tagged by a zero
  251.  
  252. NUMBER_STRING:
  253.  
  254.       PUSH      BX               ; save registers used
  255.       PUSH      DX
  256.       PUSH      DI
  257.       PUSH      ES
  258.  
  259.  
  260. ;      ...      1) store character count and mark the flag for type of i/o
  261.  
  262.       DEC      SI               ; backup to start of string
  263.       MOV      CHAR_COUNT,80        ; always less than 80 characters
  264.       OR      LOCAL_FLAG,ZERO_TAGGED
  265.       MOV      RESIDUAL,CX           ; restore original cx contents when done
  266.       JMP      SETUP_START
  267.  
  268.  
  269. ; ----------
  270.  
  271.  
  272. ;    repeated blanks sent to screen
  273.  
  274. REPEAT_BLANKS:
  275.  
  276.       PUSH      BX               ; save registers used
  277.       PUSH      DX
  278.       PUSH      DI
  279.       PUSH      ES
  280.  
  281.  
  282. ;      ...      1) store character count and mark the flag for type of i/o
  283.  
  284.       MOV      CHAR_COUNT,CX        ; save character count
  285.       OR      LOCAL_FLAG,JUST_BLANKS
  286.       MOV      RESIDUAL,1           ; leave one in cx register when done
  287.       JMP      SETUP_START
  288.  
  289.  
  290. ; ----------
  291.  
  292.  
  293. ;    write the string for basic
  294.  
  295. STRING_IO:
  296.  
  297.       PUSH      BX               ; save registers used,
  298.       PUSH      DX
  299.       PUSH      DI
  300.       PUSH      ES
  301.  
  302.  
  303.  
  304. ;      ...      1) backup to start of string and store character count
  305.  
  306.       DEC      SI               ; backup to start of string
  307.       MOV      CHAR_COUNT,CX        ; save character count
  308.       MOV      RESIDUAL,1           ; leave one in cx register when done
  309.  
  310.  
  311. ;      ...      2) load current page from DS:[0085]
  312.  
  313. SETUP_START:
  314.       MOV      BL,BYTE PTR DS:[0085h]    ; load current page
  315.       SUB      BH,BH
  316.       SHL      BX,1               ; convert to a table offset
  317.       MOV      DI,PAGE_START[BX]    ; load start of page
  318.       MOV      STARTING_PAGE,DI     ; save the page
  319.       MOV      END_OF_PAGE,DI       ; save ending page pointer
  320.       ADD      END_OF_PAGE,4000
  321.  
  322.  
  323.  
  324. ;      ...      3) load current position on page from DS:[0087]
  325.  
  326.       MOV      DX,WORD PTR DS:[0087h]    ; load current position
  327.       DEC      DH               ; basic counts from 1 instead of 0
  328.       DEC      DL               ; basic counts from 1 instead of 0
  329.       MOV      BL,DL            ; load row number
  330.       SHL      BX,1               ; two bytes per table entry
  331.       ADD      DI,LINE_START[BX]    ; add in start of line
  332.       MOV      STARTING_LINE,DI     ; store this for later
  333.  
  334.  
  335.       MOV      DL,DH            ; bring down column number
  336.       SUB      DH,DH
  337.       ADD      DI,DX            ; add in column position
  338.       ADD      DI,DX            ; account for attribute bytes
  339.  
  340.  
  341.  
  342. ;      ...      4) load attribute for string from DS:[00B5]
  343.  
  344.       MOV      BH,BYTE PTR DS:[00B5h]  ; load attribute for string
  345.  
  346.  
  347.  
  348. ;      ...      5) move character count to CX for use in loop
  349.  
  350.       MOV      CX,CHAR_COUNT        ; load the character count
  351.  
  352.  
  353.  
  354. ;      ...      6) load type of crt display from 0000:463
  355.  
  356.       SUB      AX,AX            ; address system memory
  357.       MOV      ES,AX
  358.  
  359.       MOV      DX,WORD PTR ES:[463h]      ; load address of display adapter
  360.       ADD      DX,6                 ; address crt status port
  361.  
  362.  
  363. ;      ...      7) address the screen segment
  364.  
  365.       MOV      AX,0B000h           ; screen seg for monochrome card
  366.       CMP      DX,03DAh           ; is this a graphic card?
  367.       JNE      MONOCHROME
  368.  
  369.       MOV      AX,0B800h           ; load screen seg for graphic card
  370.  
  371. MONOCHROME:
  372.  
  373.       MOV      ES,AX            ; address the screen buffer
  374.  
  375.  
  376.  
  377. ;      ...      8) move string to screen while synchronizing
  378. ;              with horizontal retrace
  379.  
  380.       TEST      LOCAL_FLAG,JUST_BLANKS
  381.       JZ      DISPLAY_LOOP
  382.  
  383.       MOV      BL,20h           ; load a blank
  384. BLANK_LOOP:
  385.       CALL      DISPLAY_CHAR           ; display a line of blanks for basic
  386.       LOOP      BLANK_LOOP
  387.       JMP      UPDATE_POSITION
  388.  
  389.  
  390. DISPLAY_LOOP:
  391.       LODSB                ; load next character
  392.  
  393.       CMP      AL,20h           ; special character?
  394.       JGE      NOT_SPECIAL
  395.       CALL      SPECIAL
  396.       JZ      ANOTHER_CHAR           ; if flag set, go for another character
  397.  
  398. NOT_SPECIAL:
  399.  
  400.       MOV      BL,AL
  401.  
  402.       CLI
  403. HSYNC_WAIT1:
  404.       IN      AL,DX            ; check for horizontal retrace
  405.       TEST      AL,1
  406.       JNZ      HSYNC_WAIT1           ; wait for retrace
  407. HSYNC_WAIT2:
  408.       IN      AL,DX            ; check for horizontal retrace
  409.       TEST      AL,1
  410.       JZ      HSYNC_WAIT2           ; wait for retrace
  411.  
  412.       MOV      AX,BX
  413.       STOSW                ; store character and attribute
  414.  
  415. ANOTHER_CHAR:
  416.       STI
  417.  
  418.       CMP      DI,END_OF_PAGE
  419.       JL      NOT_SCROLLED
  420.  
  421.       MOV      AL,0Dh           ; force a carriage return
  422.       CALL      SPECIAL
  423.  
  424. NOT_SCROLLED:
  425.  
  426.       LOOP      DISPLAY_LOOP           ; repeat cx times
  427.  
  428.  
  429.  
  430. ;      ...     9) update cursor position on screen
  431.  
  432.  
  433. UPDATE_POSITION:
  434.       MOV      AX,DI
  435.       SUB      AX,STARTING_PAGE
  436.       SHR      AX,1               ; eliminate attribute bytes
  437.       SUB      DX,DX
  438.       MOV      BX,80            ; divide by bytes per line
  439.       DIV      BX               ;   quotient in AL (ROW)
  440.                        ;   remainder in DL (COLUMN)
  441.       MOV      DH,AL
  442.       MOV      BH,BYTE PTR DS:[0085h]    ; load page number
  443.       MOV      AH,2               ; request new position
  444.       INT      10h
  445.  
  446.  
  447. ;      ...      10) update cursor position in database at DS:[0087]
  448.  
  449.       XCHG      DH,DL            ; basic likes this reversed
  450.       INC      DH               ; basic counts from 1 instead of 0
  451.       INC      DL               ; basic counts from 1 instead of 0
  452.       MOV      WORD PTR DS:[0087h],DX
  453.  
  454.  
  455. ;      ...      11) leave registers in manner BASIC expects
  456.  
  457.       MOV      CX,RESIDUAL           ; let decrement instr take this to zero
  458.                        ;  inside basic
  459.       POP      ES
  460.       POP      DI
  461.       POP      DX
  462.  
  463.       POP      BX
  464.       POP      BP
  465.  
  466.  
  467.       ADD      SP,4               ; throw away offset and code segment
  468.                        ;  from our call
  469.  
  470.       POP      AX               ; throw away near call on stack
  471.       PUSH      BASIC_SEGMENT        ; and convert to a far call
  472.       PUSH      AX
  473.       RET                   ; return to basic
  474.  
  475.  
  476. PRINTER   ENDP
  477.  
  478. ;______________________________________________________________________________
  479.  
  480. ;  subroutine to handle special control characters
  481.  
  482. SPECIAL   PROC      NEAR
  483.  
  484. ; ----------
  485.  
  486.       CMP      AL,0Ah           ; line feed?
  487.       JE      NEW_LINE
  488.  
  489.  
  490. ; ----------
  491.  
  492.       CMP      AL,0Bh           ; home?
  493.       JNE      NOT_HOME
  494.       MOV      DI,STARTING_PAGE     ; start over at top of screen
  495.       MOV      STARTING_LINE,DI
  496.       SUB      AL,AL
  497.       RET
  498.  
  499. NOT_HOME:
  500.  
  501. ; ----------
  502.  
  503.       CMP      AL,0Ch           ; clear screen?
  504.       JNE      NOT_CLEAR
  505.       MOV      DI,STARTING_PAGE
  506.       MOV      STARTING_LINE,DI
  507.       MOV      AL,0               ; clear whole window
  508.       JMP      SHORT SCROLL_SCREEN
  509.  
  510.  
  511. NOT_CLEAR:
  512.  
  513. ; ----------
  514.  
  515.       CMP      AL,0Dh           ; carriage return?
  516.       JNE      NOT_CR
  517.  
  518. NEW_LINE:
  519.       MOV      DI,STARTING_LINE
  520.       ADD      DI,160
  521.       JMP      SHORT TEST_RIGHT
  522.  
  523. NOT_CR:
  524.  
  525. ; ----------
  526.  
  527.       CMP      AL,1Ch           ; move right?
  528.       JNE      NOT_RIGHT
  529.       ADD      DI,2
  530.       JMP      SHORT TEST_RIGHT
  531.  
  532. NOT_RIGHT:
  533.  
  534. ; ----------
  535.  
  536.       CMP      AL,1Dh           ; move left?
  537.       JNE      NOT_LEFT
  538.       SUB      DI,2
  539.       JMP      SHORT TEST_LEFT
  540.  
  541. NOT_LEFT:
  542.  
  543. ; ----------
  544.  
  545.       CMP      AL,1Eh           ; move up?
  546.       JNE      NOT_UP
  547.  
  548.       SUB      DI,160
  549.       JMP      SHORT TEST_LEFT
  550.  
  551. NOT_UP:
  552.  
  553. ; ----------
  554.  
  555.       CMP      AL,1Fh           ; move down?
  556.       JNE      NOT_DOWN
  557.  
  558.       ADD      DI,160
  559.       JMP      SHORT TEST_RIGHT
  560.  
  561. NOT_DOWN:
  562.       JMP      SHORT TEST_FOR_TAB
  563.  
  564. ; ----------
  565.  
  566. TEST_RIGHT:
  567.       CMP      DI,END_OF_PAGE       ; are we past line 25?
  568.       JL      VALID_RIGHT
  569.       MOV      DI,STARTING_PAGE     ; back at start of last line
  570.       ADD      DI,3840
  571.       MOV      STARTING_LINE,DI
  572.  
  573.       MOV      AL,1               ; scroll one line
  574.       JMP      SHORT SCROLL_SCREEN
  575.  
  576. VALID_RIGHT:
  577.       SUB      AL,AL
  578.       RET
  579.  
  580. ; ----------
  581.  
  582. SCROLL_SCREEN:
  583.       PUSH      CX
  584.       MOV      CX,0               ; start in upper left corner
  585.       PUSH      DX
  586.       MOV      DX,184Fh           ; end in lower right
  587.       MOV      AH,6
  588.       PUSHF                ; simulate an INT 10
  589.       CALL      DWORD PTR ORIG_INT10
  590.       POP      DX
  591.       POP      CX
  592.       SUB      AL,AL
  593.       RET
  594.  
  595. ; ----------
  596.  
  597. TEST_LEFT:
  598.       CMP      DI,STARTING_PAGE
  599.       JGE      VALID_LEFT
  600.  
  601.       MOV      DI,STARTING_PAGE
  602.  
  603. VALID_LEFT:
  604.       SUB      AL,AL
  605.       RET
  606.  
  607. ; ----------
  608.  
  609. TEST_FOR_TAB:
  610.  
  611.       CMP      AL,09h           ; tab?
  612.       JNE      NOT_TAB
  613.  
  614.       PUSH      CX
  615.       PUSH      DX
  616.       MOV      AX,DI
  617.       SUB      AX,STARTING_LINE
  618.       SHR      AX,1               ; discount attribute bytes
  619.       SUB      DX,DX
  620.       MOV      CX,8
  621.       DIV      CX
  622.       MOV      CX,8               ; tab positions are every 8 charactes
  623.       SUB      CX,DX            ; subtract off remainder
  624.       MOV      BL,' '               ; write some blanks
  625.       POP      DX
  626. TAB_LOOP:
  627.       CALL      DISPLAY_CHAR
  628.       LOOP      TAB_LOOP
  629.  
  630.       POP      CX
  631.       SUB      AL,AL
  632.       RET
  633.  
  634. NOT_TAB:
  635.  
  636. ; ----------
  637.  
  638.       CMP      AL,08h           ; backspace?
  639.       JNE      NOT_BACKSPACE
  640.  
  641.       CMP      DI,STARTING_LINE
  642.       JE      AT_START
  643.       SUB      DI,2               ; back up a space
  644.  
  645. AT_START:
  646.       MOV      BL,' '               ; write a blank
  647.       CALL      DISPLAY_CHAR
  648.  
  649.       SUB      DI,2               ; back up a space
  650.       SUB      AL,AL
  651.       RET
  652.  
  653. NOT_BACKSPACE:
  654.  
  655. ; ----------
  656.  
  657.       CMP      AL,00h           ; null?
  658.       JNE      NOT_NULL
  659.  
  660.       TEST      LOCAL_FLAG,ZERO_TAGGED  ; does this mean end of string?
  661.       JZ      NOT_NULL          ;  branch if null meaningless
  662.       MOV      CX,1               ; terminate the display loop
  663.       DEC      SI               ; backup so basic can see null too
  664.       SUB      AL,AL
  665.       RET
  666.  
  667. NOT_NULL:
  668.  
  669. ; ----------
  670.  
  671.       MOV      AH,2
  672.       SUB      AH,1               ; set flag to display the char
  673.       RET
  674.  
  675. SPECIAL   ENDP
  676.  
  677. ;______________________________________________________________________________
  678.  
  679. ;  routine to display a character in BL - used only for special characters
  680. ;     attribute is in BH
  681.  
  682.  
  683. DISPLAY_CHAR      PROC    NEAR
  684.  
  685.       CLI
  686. HSYNC_WAIT3:
  687.       IN      AL,DX            ; check for horizontal retrace
  688.       TEST      AL,1
  689.       JNZ      HSYNC_WAIT3           ; wait for retrace
  690. HSYNC_WAIT4:
  691.       IN      AL,DX            ; check for horizontal retrace
  692.       TEST      AL,1
  693.       JZ      HSYNC_WAIT4           ; wait for retrace
  694.  
  695.       MOV      AX,BX
  696.       STOSW                ; store character and attribute
  697.  
  698.       STI
  699.       RET
  700.  
  701. DISPLAY_CHAR      ENDP
  702.  
  703.  
  704. ;______________________________________________________________________________
  705.  
  706. LASTADDR  LABEL   BYTE
  707.  
  708.  
  709. COPYRIGHT LABEL   BYTE
  710.       DB      10,13
  711.       DB  '         CLUBware  (tm)',10,13,10,13
  712.       DB  'COMPRINT - Enhancement to the Basic Compiler Print statement'
  713.       DB      10,13
  714.       DB  '                 (for routines compiled without /O option)'
  715.       DB      10,13,10,13
  716.       DB  '         Copyright 1984 Rayhawk Automation N.W. Inc',10,13
  717.       DB  '                        P.O. Box 1427',10,13
  718.       DB  '                        Beaverton, Oregon   97075',10,13,'$'
  719.  
  720.  
  721. ;______________________________________________________________________________
  722.  
  723. COMPRINT  PROC      FAR
  724.  
  725.  
  726.       PUSH      DS               ; Push addr of Program Segment Prefix
  727.       SUB      AX,AX            ; Zero AX
  728.       PUSH      AX               ; Push zero onto stack
  729. ;                     (offset of INT 20 within PSP)
  730.  
  731.  
  732. ;              | - - - - - - - - - - - - - - - - - - - - - - - - -|
  733. ;              |                          |
  734. ;              |        take over the INT 10h         |
  735. ;              |        interrupt if not already done     |
  736. ;              |                          |
  737. ;              | - - - - - - - - - - - - - - - - - - - - - - - - -|
  738.  
  739.       MOV      DS,AX            ; address low memory
  740.  
  741. ;      CMP      WORD PTR DS:[40h],OFFSET INTSWAP
  742. ;      JE      ALREADY_DONE
  743.  
  744.       MOV      AX,WORD PTR DS:[40h] ; save original int10
  745.       MOV      ORIG_INT10,AX
  746.       MOV      AX,WORD PTR DS:[42h]
  747.       MOV      ORIG_INT10+2,AX
  748.  
  749.       MOV      AX,SEG COMPRINT
  750.       MOV      DS,AX
  751.       MOV      DX,OFFSET INTSWAP    ; Load offset of interrupt service mod
  752.       MOV      AX,2510h           ; Prepare for DOS service call type 25
  753. ;                     to establish service for INT 10
  754.       INT      21h               ; Ask DOS to establish service
  755.  
  756. ;              | - - - - - - - - - - - - - - - - - - - - - - - - -|
  757. ;              |                          |
  758. ;              |        issue copyright message         |
  759. ;              |                          |
  760. ;              | - - - - - - - - - - - - - - - - - - - - - - - - -|
  761.  
  762.       MOV      DX,OFFSET COPYRIGHT
  763.       MOV      AH,9
  764.       INT      21h
  765.  
  766.  
  767. ;              | - - - - - - - - - - - - - - - - - - - - - - - - -|
  768. ;              |                          |
  769. ;              |        modify INT 20 into INT 27 in the     |
  770. ;              |        program segment prefix         |
  771. ;              |                          |
  772. ;              | - - - - - - - - - - - - - - - - - - - - - - - - -|
  773.  
  774.       MOV      BYTE PTR ES:[01],27h ; Change INT 20h to INT 27h
  775.  
  776. ;              | - - - - - - - - - - - - - - - - - - - - - - - - -|
  777. ;              |                          |
  778. ;              |     6) load address of ending tag into DX     |
  779. ;              |                          |
  780. ;              | - - - - - - - - - - - - - - - - - - - - - - - - -|
  781.  
  782.       MOV      AX,SEG LASTADDR
  783.       SUB      AX,SEG COMPRINT
  784.       MOV      CL,4               ; prepare for 4 bit shift
  785.       SHL      AX,CL            ; shift up (convert from seg to abs)
  786.       ADD      AX,OFFSET LASTADDR   ; add address of bottom location
  787.       ADD      AX,0103h           ; Pad offset because DOS measures
  788. ;                      offset relative to Program
  789. ;                      Segment Prefix
  790.       MOV      DX,AX            ; leave where DOS will find it
  791.  
  792. ;              | - - - - - - - - - - - - - - - - - - - - - - - - -|
  793. ;              |                          |
  794. ;              |     7) use RET FAR to return to DOS and     |
  795. ;              |        leave service routine resident     |
  796. ;              |                          |
  797. ;              | - - - - - - - - - - - - - - - - - - - - - - - - -|
  798.  
  799. ALREADY_DONE:
  800.  
  801.       RET
  802.  
  803. COMPRINT  ENDP
  804.  
  805. SCRDSEG   ENDS
  806.  
  807. ;______________________________________________________________________________
  808.  
  809. STACK      SEGMENT PARA STACK 'STACK'
  810.       DB      24 DUP('STACK***')
  811. TOPSTACK  DB      0
  812. STACK      ENDS
  813.  
  814.       END      COMPRINT
  815.